简明Python教程(A Byte of Python中文版)
参考资料地址:https://github.com/LenKiMo/byte-of-python(中文版)
https://github.com/swaroopch/byte-of-python(英文版)
https://python.swaroopch.com/(英文版)
注意点:
1. Python特点:解释性语言(无需编译成二进制码,直接源码->字节码->电脑语言)、强面向对象 //字节码文件以.pyc为扩展名,独立于运行平台
2. 变量:无需声明或定义数据类型;没有long和char类型
3. 格式化方法:format()函数
4. 换行连接
- 显示行连接:利用"\"连接多行 //后面立即接换行
- 隐式行连接:以括号开始的多行
5. Python 对块使用缩进,不使用大括号,同一组语句(块)缩进必须相同 //建议统一用四个空格进行缩进
6. 运算符:整除为“//”
7. 控制流:Python不存在switch语句;while和for语句可以拥有else子句
8. 函数
(1)函数参数:
- 定义函数时给定的名称称作“形参”,调用函数时提供给函数的值称作“实参”
- 默认参数值:在定义时进行赋值 //有默认参数值的参数必须位于参数列表的末尾
- 关键字参数:使用命名(关键字)而非位置来指定函数中的参数 //优点:无需考虑参数顺序;仅需对部分指定参数进行赋值,其他的参数使用默认值
- 可变参数(参数数量是可变的):def func(param1, *param2, **param3),如:
1 def total(a=5, *numbers, **phonebook): 2 print('a', a) 3 #遍历元组中的所有项目 4 for single_item in numbers: 5 print('single_item', single_item) 6 #遍历字典中的所有项目 7 for first_part, second_part in phonebook.items(): 8 print(first_part,second_part) 9 print(total(10,1,2,3,Jack=1123,John=2231,Inge=1560))
其中,*param2参数表明所有未指定的位置参数将构成名称为“param2”的元组(Tuple),而**param3则表明所有未指定的关键字参数将构成名字为“param3”的字典(dictionary)
(2)变量作用域
局部变量:变量的作用域为被定义的块,如函数内变量
全局变量:使用global语句进行声明后再使用
(3)文档字符串(DocStrings):用于在函数定义开始对程序功能进行说明,如 def print_max(x, y):
2 '''Prints the maximum of two numbers.打印两个数值中的最大数。 3 The two values must be integers.这两个数都应该是整数''' 4 # 如果可能,将其转换至整数类型 5 x = int(x) 6 y = int(y) 7 if x > y: 8 print(x, 'is maximum') 9 else: 10 print(y, 'is maximum') 11 12 print_max(3, 5) 13 print(print_max.__doc__) #使用函数对象的__doc__属性 ,也可使用help函数:help(print_max),或者pydoc命令
注:文档字符串一般约定为一串多行字符串,其中第一行以某一大写字母开始,以句号结束。第二行为空行,后跟的第三行开始是任何详细的解释说明。
9. 模块(以.py为后缀名,包含函数与变量的文件)
(1)导入模块
- (建议)利用import语句导入模块:如import sys //Python从当前程序目录和sys.path变量所提供的目录进行模块搜索;sys.path的值与环境变量PYTHONPATH等同
- 利用from...import...语句 //应避免使用,防止程序中出现命名冲突
- 利用from...import *导入模块中所有公共名称 //避免使用
(2)常用模块
import os, time
- print(os.getcwd()) //输出当前目录
- os.sep //当前操作系统所采用的分隔符(便于程序可移植),Linux为“/”,Windows为“\\”(转义\),Mac为“:”
- os.path.exists() //判断目录路径是否存在
- os.mkdir() //创建目录
- time.strftime() //将当前日期转化为字符串,可以设置显示格式
- os.system() //使命令从系统中运行,如shell
- os.remove() //删除文件
(3)模块的名称__name__属性,用于确定所在模块的名称,如利用__name__确定模块是独立运行还是被导入进来运行:
1 if __name__ == '__main__': 2 print('This program is being run by itself') 3 else: 4 print('I am being imported from another module')
注:每一个 Python 模块都定义了它的 __name__ 属性。如果它与 __main__ 属性相同则代表这一模块是由用户独立运行的
(4)dir()函数 //内置函数返回由对象所定义的名称列表,如果参数是模块名称,函数将返回这一指定模块的名称列表(函数、类、变量);如果没有提供参数,函数将返回当前模块的名称列表。 //del语句用于删除变量或名称,如del a
(5)包(Packages):组织模块的层次结构 //from 包.模块 import ... 需要包文件夹位于python的搜索路径——环境变量PYTHONPATH中
包是指一个包含模块与一个特殊的__init__.py文件的文件夹 //__init__.py表明这一文件夹包含Python模块
#创建一个名为“world”的包,其中还包含着 “asia”、“africa”等其它子包
#同时这些子包都包含了诸如“india”、“madagascar”等模块。
1 - <some folder present in the sys.path>/ 2 - world/ 3 - __init__.py 4 - asia/ 5 - __init__.py 6 - india/ 7 - __init__.py 8 - foo.py 9 - africa/ 10 - __init__.py 11 - madagascar/ 12 - __init__.py 13 - bar.py
10. 数据结构
(1)列表(可变数据类型):利用方括号定义,如shoplist = ['apple', 'mango', 'carrot', 'banana'] //help(list)查看更多细节
(2)元组(不可变数据类型):将多个对象保存在一起,建议利用圆括号定义,如zoo = ('python', 'elephant', 'penguin'),单项目元组 singleton = (2, ) //help(tuple)
(3)字典(可变数据类型):存储“键-值”对(类似地址簿),利用花括号定义,如d = {key : value1 , key2 : value2},其中键必须是不可变的对象(如字符串),且字典中不同“键-值”对是无序的 //help(dict)
(4)序列:列表、元组和字符串均可以看作序列(Sequence)的某种表现形式,序列的主要功能是资格测试(in和not in表达式)和索引操作(从0开始)
(5)集合:简单对象的无序集合,如bri = set(['brazil', 'russia', 'india']) //help(set)
(6)利用变量创建对象,变量仅仅是对对象的一个引用(refer),即变量名仅指向对象在内存中的地址,也被视为将名称绑定(Binding)到对象上;示例代码如下:
1 print('Simple Assignment') 2 shoplist = ['apple', 'mango', 'carrot', 'banana'] 3 # mylist 只是指向同一对象的另一种名称 4 mylist = shoplist #简单赋值,不创建副本 5 # 我购买了第一项项目,所以我将其从列表中删除 6 del shoplist[0] 7 print('shoplist is', shoplist) 8 print('mylist is', mylist) 9 # 注意到 shoplist 和 mylist 二者都 10 # 打印出了其中都没有 apple 的同样的列表,以此我们确认 11 # 它们指向的是同一个对象 12 print('Copy by making a full slice') 13 # 通过生成一份完整的切片制作一份列表的副本 14 mylist = shoplist[:] #切片操作创建新的副本 15 # 删除第一个项目 16 del mylist[0] 17 print('shoplist is', shoplist) 18 print('mylist is', mylist) 19 # 注意到现在两份列表已出现不同
注:列表等复杂对象的赋值语句只是对同一对象的“查阅”,如果需要创建副本,必须使用切片操作制作副本
11. 面向对象编程
对象(object)是类(class)的实例(instance),包含两种属性(attribute):字段(变量)、方法(函数)
(1)类方法和普通函数的区别:类方法的第一个参数必须为self(引用对象本身)且不可缺省,但是调用时无需显式赋值 //相当于C++中的指针以及Java与C#中的this指针
(2)__init__()方法:进行对象初始化,且无需显式调用 //前后均为双下划线
1 class Person: 2 def __init__(self, name): #无需显式调用 3 self.name = name 4 def say_hi(self): 5 print('Hello, my name is', self.name) 6 7 p = Person('Swaroop') 8 p.say_hi() 9 # 前面两行同时也能写作 10 # Person('Swaroop').say_hi()
(3)类变量和对象变量:类变量为该类的所有实例共享,对象变量为类的实例对象独立拥有
1 # coding=UTF-8 2 class Robot: 3 """表示有一个带有名字的机器人。""" 4 # 一个类变量,用来计数机器人的数量 5 population = 0 6 def __init__(self, name): 7 """初始化数据""" 8 self.name = name 9 print("(Initializing {})".format(self.name)) 10 # 当有人被创建时,机器人 11 # 将会增加人口数量 12 Robot.population += 1 #等同于self.__class__.population += 1 13 14 def die(self): 15 """我挂了。""" 16 print("{} is being destroyed!".format(self.name)) 17 Robot.population -= 1 18 if Robot.population == 0: 19 print("{} was the last one.".format(self.name)) 20 else: 21 print("There are still {:d} robots working.".format(Robot.population)) 22 23 def say_hi(self): 24 """来自机器人的诚挚问候 25 没问题,你做得到。""" 26 print("Greetings, my masters call me {}.".format(self.name)) 27 28 @classmethod #类方法,使用装饰器Decorator将how_many标记为类方法 29 def how_many(cls): 30 """打印出当前的人口数量""" 31 print("We have {:d} robots.".format(cls.population)) 32 33 droid1 = Robot("R2-D2") 34 droid1.say_hi() 35 Robot.how_many() 36 37 droid2 = Robot("C-3PO") 38 droid2.say_hi() 39 Robot.how_many() 40 41 print("\nRobots can do some work here.\n") 42 print("Robots have finished their work. So let's destroy them.") 43 droid1.die() 44 droid2.die() 45 46 Robot.how_many()
注:
- 所有的类成员都是公开的,如果使用数据成员并在其名字中使用双下划线作为前缀,形成诸如 __privatevar这样的形式,Python会使用名称调整来使其有效地成为一个私有变量;因此,建议遵循如下约定:任何在类或对象之中使用的变量其命名应以下划线开头,其它所有非此格式的名称都将是公开的,并可以为其它任何类或对象所使用。
- 装饰器(Decorators)是应用包装函数的快捷方式,有助于将某一功能与一些代码一遍又一遍地“包装”
- python装饰器的通俗理解:https://blog.csdn.net/u013471155/article/details/68960244
(4)继承:基类/超类、派生类/子类、多态性(子类型对象可以看作父类的实例)
1 # coding=UTF-8 2 class SchoolMember: 3 '''代表任何学校里的成员。''' 4 def __init__(self, name, age): 5 self.name = name 6 self.age = age 7 print('(Initialized SchoolMember: {})'.format(self.name)) 8 9 def tell(self): 10 '''告诉我有关我的细节。''' 11 print('Name:"{}" Age:"{}"'.format(self.name, self.age), end=" ") 12 13 class Teacher(SchoolMember): #继承,参数为包含基类名称的元组 14 '''代表一位老师。''' 15 def __init__(self, name, age, salary): 16 SchoolMember.__init__(self, name, age) #子类定义__init__的情况下需要显式调用父类构造函数__init__ 17 self.salary = salary 18 print('(Initialized Teacher: {})'.format(self.name)) 19 20 def tell(self): 21 SchoolMember.tell(self) #子类对象作为父类方法的实例参数 22 print('Salary: "{:d}"'.format(self.salary)) 23 24 class Student(SchoolMember): 25 '''代表一位学生。''' 26 def __init__(self, name, age, marks): 27 SchoolMember.__init__(self, name, age) 28 self.marks = marks 29 print('(Initialized Student: {})'.format(self.name)) 30 31 def tell(self): 32 SchoolMember.tell(self) 33 print('Marks: "{:d}"'.format(self.marks)) 34 35 t = Teacher('Mrs. Shrividya', 40, 30000) 36 s = Student('Swaroop', 25, 75) 37 # 打印一行空白行 38 print() 39 40 members = [t, s] 41 for member in members: 42 # 对全体师生工作 43 member.tell()
12. 输入与输出
(1)用户输入内容:input()函数
(2)文件:创建(open)一个属于file类的对象并适当使用它的read、readline、write方法
1 poem = '''\ 2 Programming is fun 3 When the work is done 4 if you wanna make your work also fun: 5 use Python! 6 ''' 7 8 # 打开文件以编辑('w'riting) 9 f = open('poem.txt', 'w') 10 # 向文件中编写文本 11 f.write(poem) 12 # 关闭文件,保证内容已经被写入到文件 13 f.close() 14 15 # 如果没有特别指定, 16 # 将假定启用默认的阅读('r'ead)模式 17 f = open('poem.txt') 18 while True: 19 line = f.readline() 20 # 零长度指示 EOF 21 if len(line) == 0: 22 break 23 # 每行(`line`)的末尾 24 # 都已经有了换行符 25 #因为它是从一个文件中进行读取的 26 print(line, end='') 27 # 关闭文件 28 f.close()
(3)pickle标准模块:将任何纯Python对象存储到一个文件中,并在稍后将其取回
1 import pickle 2 3 # The name of the file where we will store the object 4 shoplistfile = 'shoplist.data' 5 # The list of things to buy 6 shoplist = ['apple', 'mango', 'carrot'] 7 8 # Write to the file 9 f = open(shoplistfile, 'wb') 10 # Dump the object to a file 11 pickle.dump(shoplist, f) #封装 12 f.close() 13 14 # Destroy the shoplist variable 15 del shoplist 16 17 # Read back from the storage 18 f = open(shoplistfile, 'rb') 19 # Load the object from the file 20 storedlist = pickle.load(f) #拆封 21 print(storedlist)
13. 异常
(1)try..except...语句:检查语句,并根据异常类型进行相应的处理
1 try: 2 text = input('Enter something --> ') #需要检查的语句块 3 except EOFError: #捕获异常类型 4 print('Why did you do an EOF on me?') 5 except KeyboardInterrupt: 6 print('You cancelled the operation.') 7 else: 8 print('You entered {}'.format(text))
(2)raise语句:主动抛出异常对象,引发异常处理
1 # encoding=UTF-8 2 3 class ShortInputException(Exception): #继承自Exception类 4 '''一个由用户定义的异常类''' 5 def __init__(self, length, atleast): 6 Exception.__init__(self) 7 self.length = length 8 self.atleast = atleast 9 10 try: 11 text = input('Enter something --> ') 12 if len(text) < 3: 13 raise ShortInputException(len(text), 3) #抛出自定义异常 14 # 其他工作能在此处继续正常运行 15 except EOFError: 16 print('Why did you do an EOF on me?') 17 except ShortInputException as ex: #捕获自定义异常 18 print(('ShortInputException: The input was ' + '{0} long, expected at least {1}').format(ex.length, ex.atleast)) 19 else: 20 print('No exception was raised.')
(3)try...finally...:确保finally出的语句块被执行,例如确保文件对象的正确关闭
1 import sys 2 import time 3 4 f = None 5 try: 6 f = open("poem.txt") 7 # 我们常用的文件阅读风格 8 while True: 9 line = f.readline() 10 if len(line) == 0: 11 break 12 print(line, end='') 13 sys.stdout.flush() #将输出立即打印到屏幕 14 print("Press ctrl+c now") 15 # 为了确保它能运行一段时间 16 time.sleep(2) #休眠两秒 17 except IOError: 18 print("Could not find file poem.txt") 19 except KeyboardInterrupt: 20 print("!! You cancelled the reading from the file.") 21 finally: #该部分子句一定会执行 22 if f: 23 f.close() 24 print("(Cleaning up: Closed the file)")
注:确保文件关闭的快捷方式——with语句(避免显示调用try...finally语句)
#with语句会获取由open语句返回的对象‘thefile’,并在代码块开始前调用thefile.__enter__函数,在代码块执行完毕之后调用thefile.__exit__
1 with open("poem.txt") as f: #将关闭文件的操作交由with open来自动完成(__exit__方法) 2 for line in f: 3 print(line, end='')
14. 标准库(https://docs.python.org/3/library/)
(1)sys模块:
sys.argv:命令行参数,如查看Python软件版本sys.version_info
(2)logging日志模块:用于记录信息
(3)os模块:用于和操作系统交互
(4)platform模块:用于获取平台(操作系统)的信息
1 import os 2 import platform 3 import logging 4 5 if platform.platform().startswith('Windows'): #返回正在使用的操作系统 6 logging_file = os.path.join(os.getenv('HOMEDRIVE'), os.getenv('HOMEPATH'), 'test.log') 7 else: 8 logging_file = os.path.join(os.getenv('HOME'), 'test.log') 9 10 print("Logging to", logging_file) 11 logging.basicConfig( 12 level=logging.DEBUG, 13 format='%(asctime)s : %(levelname)s : %(message)s', 14 filename=logging_file, 15 filemode='w', 16 ) 17 18 logging.debug("Start of the program") 19 logging.info("Doing something") 20 logging.warning("Dying now")
15. 更多。。。(建议参考PDF原文)
(1)函数返回多个值:传递元组
(2)特殊方法:用来模拟内置类型的某些行为
- __init__(self, ...):初始化,在新创建的对象被返回准备使用时被调用
- __del__(self):在对象被删除之前调用(它的使用时机不可预测,所以避免使用它)
- __str__(self):使用print函数时,或str()被使用时被调用
- __lt__(self, other):当小于运算符(<)被使用时被调用。类似地,其它所有运算符(+、> 等等)也存在相应的特殊方法
- __getitem__(self, key):使用x[key]索引操作时会被调用
- __len__(self):针对序列对象使用内置len()函数时会被调用
(3)单语句块:如果语句块只包括单独的一句语句时,可以在同一行指定它,如条件语句和循环语句,如if flag: print('Yes')
注:单语句块是在原地立即执行,不会被看作单独的语句块,但是会影响程序整体的工整性,不建议使用
(4)lambda语句:可以创建一个新的函数对象;从本质上说, lambda 需要一个参数,后跟一个表达式作为函数体,这一表达式执行的值将作为这个新函数的返回值
1 points = [{'x': 2, 'y': 3}, {'x': 4, 'y': 1}] 2 points.sort(key=lambda i: i['y']) #调用list的sort方法,通过获得一个key参数,用以决定列表的排序方式 3 print(points)
注:lambda表达式用于实现仅使用一次的简单函数,而无需编写独立的def块
(4)列表推导:用于从一份现有的列表中得到一份新列表,可避免显式调用循环过程,减少代码量
1 listone = [2, 3, 4] 2 listtwo = [2*i for i in listone if i > 2] 3 print(listtwo)
(5)assert语句:用于断言(判断)某事是真的;断言失败时,会抛出错误AssertionError
1 import numpy as np 2 a = np.random.randn((5,1)) 3 assert(a.shape = (5,1)) #保证数组a的大小是正确的
注:在大多数情况下,明智地选用 assert 语句好过捕获异常,也好过定位问题或向用户显示错误信息然后退出